package com.eastfair.venuebooking.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.eastfair.auth.api.UserAccountServiceFeign;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.base.entity.SuperEntity;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.venuebooking.dao.SaleClueMapper;
import com.eastfair.venuebooking.dto.*;
import com.eastfair.venuebooking.entity.BusinessOpportunity;
import com.eastfair.venuebooking.entity.Contact;
import com.eastfair.venuebooking.entity.CustomerMain;
import com.eastfair.venuebooking.entity.SaleClue;
import com.eastfair.venuebooking.enumeration.ExhibitionCustomerBusinessTypeEnum;
import com.eastfair.venuebooking.enums.SaleClueStateEnum;
import com.eastfair.venuebooking.exceptioncode.VenueBookingExceptionCode;
import com.eastfair.venuebooking.service.*;
import com.eastfair.venuebooking.vo.SaleClueVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 销售线索表
 * </p>
 *
 * @author linan
 * @date 2022-06-08
 */
@Slf4j
@Service
public class SaleClueServiceImpl extends SuperServiceImpl<SaleClueMapper, SaleClue> implements SaleClueService {

    @Resource
    private SaleClueMapper saleClueMapper;

    @Resource
    private CustomerMainService customerMainService;

    @Resource
    private ContactService contactService;

    @Resource
    private BusinessOpportunityService businessOpportunityService;

    @Resource
    private ExhibitionCustomerService exhibitionCustomerService;

    @Resource
    private UserAccountServiceFeign userAccountServiceFeign;

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<SaleClue> modelList) {
        List<Long> ids = modelList.stream()
                .map(SuperEntity::getId)
                .collect(Collectors.toList());
        if (businessOpportunityService.existBusinessOpportunityBySaleClueIds(ids)) {
            throw BizException.wrap(VenueBookingExceptionCode.BUS_EXIST_CAN_NOT_DELETE);
        }
        modelList.forEach(s -> s.setIsDeleted(BusinessConstant.YES));
        return R.successDef();
    }

    @Override
    protected R<Boolean> handlerSave(SaleClue model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setTenantId(ContextUtil.getTenantId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        return R.successDef();
    }

    @Override
    public IPage<SaleClueVO> listSaleClueVOs(PageParams<SaleClueQuery> pageParams) {
        log.info("selectSaleClueVOList - 分页查询销售线索, pageParams={}", pageParams);

        IPage<SaleClue> pageParam = pageParams.buildPage();
        SaleClueQuery query = pageParams.getModel();
        QueryWrapper<SaleClue> queryWrapper = createSaleClueQueryWrapper(query);
        IPage<SaleClueVO> page = saleClueMapper.listSaleClueVOs(pageParam, queryWrapper);

        List<SaleClueVO> saleClueVOList = page.getRecords();
        saleClueVOList.forEach(saleClueVO -> {
            // 计算未跟进天数
            if (saleClueVO.getLastFollowDate() != null) {
                int notFollowDays
                        = (int) LocalDateTimeUtil.between(saleClueVO.getLastFollowDate(), LocalDateTime.now(), ChronoUnit.DAYS);
                notFollowDays = Math.max(notFollowDays, 0);
                saleClueVO.setNotFollowDays(notFollowDays);
            }
        });
        return page;
    }

    @Override
    public SaleClueVO getSaleClueVOById(Long id) {
        log.info("selectSaleClueVOById - id查询详情, id={}", id);

        SaleClue saleClue = getById(id);
        if (saleClue == null) {
            throw BizException.wrap(VenueBookingExceptionCode.CLUE_NOT_EXIST);
        }
        SaleClueVO saleClueVO = BeanUtil.toBean(saleClue, SaleClueVO.class);
        // 创建人/更新人 信息
        R<String> createdByNameR = userAccountServiceFeign.getName(saleClue.getCreatedBy());
        saleClueVO.setCreatedByName(createdByNameR.getData());
        R<String> updatedByNameR = userAccountServiceFeign.getName(saleClue.getUpdatedBy());
        saleClueVO.setUpdatedByName(updatedByNameR.getData());

        CustomerMain customerMain = customerMainService.getById(saleClue.getCustomerId());
        if (customerMain != null) {
            saleClueVO.setCustomerName(customerMain.getCustomerCnName());
            saleClueVO.setCustomerLevel(customerMain.getCustomerLevel());
            saleClueVO.setCustomerType(customerMain.getCustomerType());
            saleClueVO.setCustomerIndustry(customerMain.getCustomerIndustry());
        }
        Contact contact = contactService.getById(saleClue.getContactId());
        if (contact != null) {
            saleClueVO.setContactName(contact.getContactName());
            saleClueVO.setContactMobile(contact.getMobile());
            saleClueVO.setContactGender(contact.getGender());
            saleClueVO.setPost(contact.getPost());
            saleClueVO.setRole(contact.getRole());
        }
        return saleClueVO;
    }

    @Override
    public SaleClue getByBusinessOpportunityId(Long businessOpportunityId) {
        BusinessOpportunity businessOpportunity = businessOpportunityService.getById(businessOpportunityId);
        if (businessOpportunity == null) {
            return null;
        }
        SaleClue saleClue = getById(businessOpportunity.getSaleClueId());
        if (saleClue == null || saleClue.getIsDeleted().equals(BusinessConstant.DELETE_YES)) {
            return null;
        }
        return saleClue;
    }

    @Override
    public boolean existSaleClue(SaleClueQuery query) {
        log.info("existSaleClue - 销售线索是否存在, query={}", query);

        QueryWrapper<SaleClue> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(SaleClue::getIsDeleted, BusinessConstant.DELETE_NO)
                .in(query.getCustomerIdList() != null && !query.getCustomerIdList().isEmpty(),
                        SaleClue::getCustomerId, query.getCustomerIdList())
                .in(query.getContactIdList() != null && !query.getContactIdList().isEmpty(),
                        SaleClue::getContactId, query.getContactIdList())
        ;
        return count(queryWrapper) > 0;
    }

    @Override
    public boolean existSaleClueByCustomerId(List<Long> customerIds) {
        SaleClueQuery query = new SaleClueQuery();
        query.setCustomerIdList(customerIds);
        return existSaleClue(query);
    }

    @Override
    public boolean existSaleClueByContactId(List<Long> contactIds) {
        SaleClueQuery query = new SaleClueQuery();
        query.setContactIdList(contactIds);
        return existSaleClue(query);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveSaleClue(SaleClueDTO saleClueDTO) {
        log.info("saveSaleClue - 保存销售线索, saleClueDTO={}", saleClueDTO);
        // 保存销售线索
        SaleClue saleClue = BeanUtil.toBean(saleClueDTO, SaleClue.class);
        save(saleClue);
        // 保存展会客户关系
        if (saleClue.getCustomerId() != null && saleClue.getExhibition() != null && StrUtil.isNotBlank(saleClue.getCustomerIdentity())) {
            saveExhibitionCustomerAndUpdateBusinessOpportunity(saleClue);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateSaleClue(SaleClueDTO saleClueDTO) {
        log.info("updateSaleClue - 更新销售线索, saleClueDTO={}", saleClueDTO);
        // 更新销售线索
        SaleClue saleClue = updateSaleClueWithoutExhibitionCustomer(saleClueDTO);
        // 更新展会客户关系
        if (saleClue.getCustomerId() != null && saleClue.getExhibition() != null && StrUtil.isNotBlank(saleClue.getCustomerIdentity())) {
            saveExhibitionCustomerAndUpdateBusinessOpportunity(saleClue);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SaleClue updateSaleClueWithoutExhibitionCustomer(SaleClueDTO saleClueDTO) {
        // 更新销售线索
        SaleClue saleClue = BeanUtil.toBean(saleClueDTO, SaleClue.class);
        updateById(saleClue);
        return saleClue;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveExhibitionCustomerAndUpdateBusinessOpportunity(SaleClue saleClue) {
        // 更新展会客户关系
        ExhibitionCustomerDTO exhibitionCustomerDTO = saveExhibitionCustomer(saleClue);
        // 更新商机
        return businessOpportunityService.updateCustomerIdentityBySaleClue(exhibitionCustomerDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ExhibitionCustomerDTO saveExhibitionCustomer(SaleClue saleClue) {
        ExhibitionCustomerDTO exhibitionCustomerDTO = new ExhibitionCustomerDTO();
        exhibitionCustomerDTO.setExhibitionId(saleClue.getExhibition());
        exhibitionCustomerDTO.setExhibitionName(saleClue.getExhibitionName());
        exhibitionCustomerDTO.setCustomerId(saleClue.getCustomerId());
        exhibitionCustomerDTO.setCustomerName(saleClue.getCustomerName());
        exhibitionCustomerDTO.setCustomerIdentity(saleClue.getCustomerIdentity());
        exhibitionCustomerDTO.setBusinessId(saleClue.getId());
        exhibitionCustomerDTO.setBusinessType(ExhibitionCustomerBusinessTypeEnum.SALE_CLUE);
        exhibitionCustomerService.saveForSaleClueOrBusinessOpportunity(exhibitionCustomerDTO);
        return exhibitionCustomerDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateFollow(SaleClueDTO updateDTO) {
        log.info("updateFollow - 更新线索得跟进信息, updateDTO={}", updateDTO);

        UpdateWrapper<SaleClue> updateWrapper = new UpdateWrapper<>();
        updateWrapper
                .lambda()
                .eq(updateDTO.getId() != null, SaleClue::getId, updateDTO.getId())
                .set(StrUtil.isNotBlank(updateDTO.getClueStatus()),
                        SaleClue::getClueStatus, updateDTO.getClueStatus())
                .set(updateDTO.getLastFollowDate() != null,
                        SaleClue::getLastFollowDate, updateDTO.getLastFollowDate())
                .set(updateDTO.getNextFollowDate() != null,
                        SaleClue::getNextFollowDate, updateDTO.getNextFollowDate())
        ;
        return update(updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateFollow(FollowRecordPlanSaveDTO saveDTO) {
        SaleClue saleClue = getById(saveDTO.getClueId());
        if (saleClue == null) {
            throw BizException.wrap(VenueBookingExceptionCode.CLUE_NOT_EXIST);
        }
        LocalDateTime lastFollowDate = FollowRecordService.getLastFollowDate(saveDTO.getFollowDateTime(), saleClue.getLastFollowDate());
        LocalDateTime nextFollowDate = saleClue.getNextFollowDate();
        if (saveDTO.getFollowPlanSaveDTO() != null) {
            nextFollowDate = FollowPlanService.getNextFollowDate(saveDTO.getFollowPlanSaveDTO().getPlanFollowDate(), saleClue.getNextFollowDate());
        }
        // 更新线索信息
        SaleClueDTO updateDTO = new SaleClueDTO();
        updateDTO.setId(saveDTO.getClueId());
        updateDTO.setClueStatus(saveDTO.getClueStatus());
        updateDTO.setLastFollowDate(lastFollowDate);
        if (saveDTO.getFollowPlanSaveDTO() != null) {
            updateDTO.setNextFollowDate(nextFollowDate);
        }
        return updateFollow(updateDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePublic(SaleCluePublicDTO publicDTO) {
        log.info("updatePublic - 移入公共, publicDTO={}", publicDTO);

        List<SaleClueDTO> updateList = publicDTO.getUpdateList();
        for (SaleClueDTO updateDTO : updateList) {
            // 更新客户
            updateDTO.setLastBelongTo(updateDTO.getBelongTo());
            updateDTO.setLastBelongToName(updateDTO.getBelongToName());
            updateDTO.setLastOrgCode(updateDTO.getOrgCode());
            updateDTO.setLastBelongToName(updateDTO.getOrgName());
            updateDTO.setBelongTo(null);
            updateDTO.setBelongToName(null);
            updateDTO.setOrgCode(null);
            updateDTO.setOrgName(null);
            updateDTO.setState(SaleClueStateEnum.PUBLIC.getCode());
            updateState(updateDTO);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateBelongTo(SaleClueAssignDTO assignDTO) {
        log.info("updateBelongTo - 更新归属人, assignDTO={}", assignDTO);

        SaleClue saleClue = getById(assignDTO.getId());
        if (saleClue == null) {
            throw BizException.wrap(VenueBookingExceptionCode.CLUE_NOT_EXIST);
        }
        SaleClueDTO updateDTO = new SaleClueDTO();
        updateDTO.setId(assignDTO.getId());
        updateDTO.setBelongTo(assignDTO.getBelongTo());
        updateDTO.setBelongToName(assignDTO.getBelongToName());
        updateDTO.setOrgCode(assignDTO.getOrgCode());
        updateDTO.setOrgName(assignDTO.getOrgName());
        updateDTO.setLastBelongTo(saleClue.getBelongTo());
        updateDTO.setLastBelongToName(saleClue.getBelongToName());
        updateDTO.setLastOrgCode(saleClue.getOrgCode());
        updateDTO.setLastOrgName(saleClue.getOrgName());
        updateDTO.setState(SaleClueStateEnum.NORMAL.getCode());
        return updateState(updateDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateBelongTo(List<SaleClueAssignDTO> list) {
        log.info("updateBelongTo - 批量更新归属人, list={}", list);
        for (SaleClueAssignDTO assignDTO : list) {
            updateBelongTo(assignDTO);
        }
        return true;
    }

    @Override
    public boolean updateState(SaleClueDTO updateDTO) {
        UpdateWrapper<SaleClue> updateWrapper = new UpdateWrapper<>();
        updateWrapper
                .lambda()
                .set(updateDTO.getState() != null, SaleClue::getState, updateDTO.getState())
                .set(SaleClue::getLastBelongTo, updateDTO.getLastBelongTo())
                .set(SaleClue::getLastBelongToName, updateDTO.getLastBelongToName())
                .set(SaleClue::getLastOrgCode, updateDTO.getLastOrgCode())
                .set(SaleClue::getLastOrgName, updateDTO.getLastOrgName())
                .set(SaleClue::getBelongTo, updateDTO.getBelongTo())
                .set(SaleClue::getBelongToName, updateDTO.getBelongToName())
                .set(SaleClue::getOrgCode, updateDTO.getOrgCode())
                .set(SaleClue::getOrgName, updateDTO.getOrgName())
                .eq(updateDTO.getId() != null, SaleClue::getId, updateDTO.getId());
        return update(updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateClueStatus(SaleClueDTO updateDTO) {
        log.info("updateClueStatus - 更新状态, updateDTO={}", updateDTO);

        UpdateWrapper<SaleClue> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda()
                .set(StrUtil.isNotBlank(updateDTO.getClueStatus()), SaleClue::getClueStatus, updateDTO.getClueStatus())
                .eq(updateDTO.getId() != null, SaleClue::getId, updateDTO.getId());
        return update(updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateCustomerIdentityByBusinessOpportunity(ExhibitionCustomerDTO exhibitionCustomerDTO) {
        SaleClue saleClue = getByBusinessOpportunityId(exhibitionCustomerDTO.getBusinessId());
        if (saleClue == null) {
            return false;
        }
        SaleClueDTO saleClueDTO = BeanUtil.toBean(saleClue, SaleClueDTO.class);
        saleClueDTO.setExhibition(exhibitionCustomerDTO.getExhibitionId());
        saleClueDTO.setExhibitionName(exhibitionCustomerDTO.getExhibitionName());
        saleClueDTO.setCustomerId(exhibitionCustomerDTO.getCustomerId());
        saleClueDTO.setCustomerName(exhibitionCustomerDTO.getCustomerName());
        saleClueDTO.setCustomerIdentity(exhibitionCustomerDTO.getCustomerIdentity());
        updateSaleClueWithoutExhibitionCustomer(saleClueDTO);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIds(List<Long> ids) {
        log.info("removeByIds - 移除线索, ids={}", ids);
        // 线索ID删除展会客户关系，并保存关联商机的展会客户关系
        exhibitionCustomerService.removeByBusinessIdsAndSaveByRelatedBusinessIds(ids, ExhibitionCustomerBusinessTypeEnum.SALE_CLUE);
        // 移除线索
        List<SaleClue> list = listByIds(ids);
        if (list == null || list.isEmpty()) {
            return true;
        }
        removeByIdsOfLogic(list);
        return true;
    }

    private QueryWrapper<SaleClue> createSaleClueQueryWrapper(SaleClueQuery query) {

        QueryWrapper<SaleClue> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .and(StrUtil.isNotBlank(query.getKeyword()), saleClueQueryWrapper -> saleClueQueryWrapper
                        .like("sc.clue_title", query.getKeyword())
                        .or()
                        .like("cm.customer_cn_name", query.getKeyword())
                        .or()
                        .like("con.contact_name", query.getKeyword())
                        .or()
                        .like("con.mobile", query.getKeyword()))
                .eq(StrUtil.isNotBlank(query.getClueSource()), "sc.clue_source", query.getClueSource())
                .eq(StrUtil.isNotBlank(query.getClueStatus()), "sc.clue_status", query.getClueStatus())
                .eq(query.getCustomerId() != null, "sc.customer_id", query.getCustomerId())
                .eq(query.getBelongTo() != null, "sc.belong_to", query.getBelongTo())
                .like(StrUtil.isNotBlank(query.getBelongToName()), "sc.belong_to_name", query.getBelongToName())
                .eq(query.getState() != null, "sc.state", query.getState())
                .between(StrUtil.isNotBlank(query.getLastFollowBeginDate())
                                && StrUtil.isNotBlank(query.getLastFollowEndDate()),
                        "sc.last_follow_date", query.getLastFollowBeginDate(), query.getLastFollowEndDate())
                .eq("sc.is_deleted", 0);
        return queryWrapper;
    }
}
